package com.ysp.summary.designpattern;

import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 *  spring的循环依赖解决
 *
 *  通过递归的方式，按顺序创建各个bean实例   创建好的 缓存起来，注入属性的时候 直接拿就好
 *
 *  核心是通过递归的方式  创建依赖的bean实例  还有创建完成的bean要缓存起来   方便注入的时候直接拿
 *
 *  spring的注册就是把对象放入缓存池 创建好的 缓存起来 即为 注册单例bean
 *
 *  思路： 先去缓存里找「Bean」，没有则「实例化当前的 Bean」放到 Map，如果有需要「依赖」当前 Bean 的，就能从 Map 取到。
 *
 * @author Administrator
 */
public class SpringCircularDependency {

    private final static Map<String,Object> cacheBean = new ConcurrentHashMap<>(4);


  public static void main(String[] args) {
    Class[] classes = {TestA.class,TestB.class};
    for (Class clas : classes) {
        getBean(clas);
    }

    System.out.println(Objects.equals(getBean(TestB.class).getA(),getBean(TestA.class)));
    System.out.println(Objects.equals(getBean(TestA.class).getB(),getBean(TestB.class)));

  }

    @SneakyThrows
    private static <T>T getBean(Class<T> clas) {
        String beanName = clas.getSimpleName().toLowerCase();
        if (cacheBean.containsKey(beanName)){
            return (T) cacheBean.get(beanName);
        }
        //将对象本身实例化
        Object beanClass = clas.getDeclaredConstructor().newInstance();
        //放入缓存
        cacheBean.put(beanName,beanClass);
        //将所有字段 需要注入的bean，创建并注入到当前bean中
        Field[] fields = beanClass.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Class<?> fieldClass = field.getType();
            String beanName2 = fieldClass.getSimpleName().toLowerCase();
//            Object bean2 = fieldClass.getDeclaredConstructor().newInstance();
            field.set(beanClass,cacheBean.containsKey(beanName2) ? cacheBean.get(beanName2) : getBean(fieldClass));
        }
        return (T)beanClass;
    }
}
